#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/11/12 16:41
# @Author : luhongxuan
# @Site :
# @File : XMLHelper.py
# @Software: PyCharm
from collections import defaultdict
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import Element, ElementTree


class XML2Dict(object):
    def __init__(self, coding='UTF-8'):
        self._coding = coding
        self.remove_ns = False
        self.contains_attr = True
        self.attr_prefix = '@'

    def _parse_node(self, t):
        ttag = t.tag
        if self.remove_ns:
            ttag = self._remove_namespace(ttag)
        d = {ttag: {} if t.attrib else None}  # the variable 'd' is the constructed target dictionary
        # 't.tag' if have values, it is the first layer of the dictionary
        children = list(t)  # The following recursive traverse processing tree, until the leaf node
        if children:  # Determine whether the node is empty, recursive boundary conditions
            dd = defaultdict(list)
            for dc in map(self._parse_node, children):  # recursive traverse processing tree
                for k, v in dc.items():
                    dd[k].append(v)
            d = {ttag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}}  # handle child node
        if self.contains_attr:
            if t.attrib:  # handle attributes,prefix all of the stored attributes @
                # d[ttag].update(('@' + k, v) for k, v in t.attrib.items())
                d[ttag].update((self.attr_prefix + k, v) for k, v in t.attrib.items())
        if t.text.strip():
            # text = t.text.strip().encode(self._coding)  # strip blank space
            text = t.text.strip()  # strip blank space
            if children or t.attrib:
                d[ttag]['#text'] = text
            else:
                d[ttag] = text  # the text value as t.tag
        return d

    def parse(self, xml_file):
        with open(xml_file, 'r') as fp:
            return self.fromstring(fp.read())

    def fromstring(self, xml_str):
        # self.remove_ns = remove_namespace
        t = ET.fromstring(xml_str)
        return self._parse_node(t)

    def _remove_namespace(self, tag):
        if tag.find("{") >= 0 and tag.find("}") >= 0:
            return tag[:tag.find("{")] + tag[(tag.find("}") + 1):]
        else:
            return tag


class XMLHelper(object):

    @staticmethod
    def dict2xml(path, my_dict, root='root', encoding='utf8'):
        elem = Element(root)  # 使用Element创建元素
        # 循环key与val
        for key, val in my_dict.items():
            # 创建新的元素,确定元素的值
            child = Element(key)
            child.text = str(val)
            # 添加为elem的子节点
            elem.append(child)

        tree = ElementTree(elem)
        # 写成xml文件
        tree.write(path, encoding=encoding)

    @staticmethod
    def xml2dict(path, remove_ns=True, contains_attr=True, attr_prefix=''):
        x2d = XML2Dict()
        x2d.remove_ns = remove_ns
        x2d.contains_attr = contains_attr
        x2d.attr_prefix = attr_prefix
        return x2d.parse(path)
